import gtk
import gobject

from main import Msn
import chat

class gui:
	"""The main User Interface of the program. Contains the login window
		and the contact list for the user."""
	
	def __init__(self):
		self.window = gtk.Window()
		self.window.connect("destroy", self.quit)
		self.main_box = gtk.VBox(False,0) # adds the sub boxes, login window has a sub box and 												conact window has a separate one
		self.window.add(self.main_box)
		self.offline_iters = {}		#makes removing users from tree list easier
		self.online_iters = {}		#makes removing users from tree list easier

		self.login_try = 1

		self.chat_window_created = 0  #if a chat window has been created or not
		self.open_chats = {}

	def quit(self, window):
		"""Quit the main program and all chats"""
		gtk.main_quit()

	def login_window(self):
		"""Function to create the login window"""
		self.login_box = gtk.VBox(False, 0)
		self.login_box.show()
		

		main_hbox = gtk.HBox(False, 25)  # Separate the DP and login fields
		main_hbox.show()

		user_dp = gtk.Image()
		MyTheme = gtk.icon_theme_get_default()
		MyIconPixbuf = MyTheme.load_icon("stock_smiley-3", 36, gtk.ICON_LOOKUP_FORCE_SVG)
		user_dp.set_from_pixbuf(MyIconPixbuf) #+ Replace to the users dp later
		user_dp.set_size_request(60,60)

		details_vbox = gtk.VBox(False, 0)  #Separate email entry and password entry
		details_vbox.show()
		bottom_hbox = gtk.HBox()	 # Separate the remember me's and login buton
		remember_vbox = gtk.VBox()	#Separate the two remember checks
		
		self.user_email = gtk.Entry()
		self.user_email.set_text("someone@somewhere.com")
		self.user_pass = gtk.Entry()
		self.user_pass.set_visibility(False)
		details_vbox.pack_start(self.user_email)
		details_vbox.pack_start(self.user_pass)

		self.remember_me = gtk.CheckButton("Remember Me")
		self.remember_pass = gtk.CheckButton("Remember Password")
		remember_vbox.pack_start(self.remember_me)
		remember_vbox.pack_start(self.remember_pass)
		bottom_hbox.pack_start(remember_vbox, False, False, 5)

		login = gtk.Button("Login")
		login.connect("clicked", self.login)
		bottom_hbox.pack_start(login, True, True)
		details_vbox.pack_end(bottom_hbox)

		main_hbox.pack_start(user_dp, False, False, 10) #Dp goes here
		main_hbox.pack_start(details_vbox, False, False, 10)

		self.login_box.pack_start(main_hbox)
		self.main_box.pack_start(self.login_box)
		self.window.set_size_request(370,200)

		self.window.show_all()
		gtk.main()

	def login(self, button):
		"""Login procedure when the login button is clicked"""
		user_email = self.user_email.get_text()
		user_password = self.user_pass.get_text()
		if self.login_try == 1: #first time we try to authenticate
			self.m = Msn(user_email, user_password, self)
			self.login_try += 1
			self.m.start()
			
		else:
			self.m.cleanup(user_email, user_password)
			self.m.login() #thread has been started..
			
	def lock_login(self):
		self.login_box.set_sensitive(False) #disable changes to the fields

	def unlock_login(self):
		self.login_box.set_sensitive(True) #disable changes to the fields


##----------------------------------------------------------------------------------------------
##				Contact Window starts Here
##--------------------------------------------------------------------------------------------
	def status_box(self):
		combobox = gtk.ComboBox()
		liststore = gtk.ListStore(gtk.gdk.Pixbuf, str)

		image = self.users_tree.render_icon(gtk.STOCK_YES, 
							gtk.ICON_SIZE_SMALL_TOOLBAR)

		liststore.append((image, "Online"))
		liststore.append((image, "Away"))
		liststore.append((image, "Busy"))
		liststore.append((image, "Hidden"))
		liststore.append((image, "Invisible"))

		combobox.set_model(liststore)


		px = gtk.CellRendererPixbuf()
		text = gtk.CellRendererText()


		combobox.pack_start(px, False)
		combobox.pack_start(text, False)

		combobox.add_attribute(px, "pixbuf", 0)
		combobox.add_attribute(text, "text", 1)

		combobox.connect("changed", self.change_state)

		return combobox

	def contact_window(self, my_instance, main_server):
		self.login_box.hide()
		self.login_box.set_no_show_all(True)
		self.box = gtk.VBox(False, 0)
		self.contact_box = gtk.VBox(False, 0)
		#self.chat = chat.Window()

		self.users_list = gtk.TreeStore(gtk.gdk.Pixbuf,
							gobject.TYPE_STRING,gobject.TYPE_STRING)

		self.users_tree = gtk.TreeView(self.users_list)	
		self.users_tree.connect("row-activated", self.start_chat) #start a chat	
		self.my_instance = my_instance
		self.ns = main_server #ns = Notification Server

		top_box = gtk.HBox(False, 0) # The buttons Add, Send, Mail

		add_box = gtk.VBox(False, 1)
		add_btn = gtk.Button("Add")
		add_btn.connect("clicked", self.new_contact)
		add_pb =  self.users_tree.render_icon(gtk.STOCK_ADD, gtk.ICON_SIZE_BUTTON)
		add_img = gtk.Image()
		add_img.set_from_pixbuf(add_pb)
		add_btn.set_relief(gtk.RELIEF_NONE)
		add_box.pack_start(add_img, False, False, 0)
		add_box.pack_start(add_btn, False, False, 0)


		send_box = gtk.VBox(False, 1)
		send_pb =  self.users_tree.render_icon(gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON)
		send_btn = gtk.Button("Send")
		send_btn.set_relief(gtk.RELIEF_NONE)
		send_img = gtk.Image()
		send_img.set_from_pixbuf(send_pb)
		send_btn.set_relief(gtk.RELIEF_NONE)
		send_box.pack_start(send_img, False, False, 0)
		send_box.pack_start(send_btn, False, False, 0)


		mail_box = gtk.VBox(False, 1)
		mail_pb =  self.users_tree.render_icon(gtk.STOCK_HOME, gtk.ICON_SIZE_BUTTON)
		mail_btn = gtk.Button("Mail")
		mail_btn.set_relief(gtk.RELIEF_NONE)
		mail_img = gtk.Image()
		mail_img.set_from_pixbuf(mail_pb)
		mail_btn.set_relief(gtk.RELIEF_NONE)
		mail_box.pack_start(mail_img, False, False, 0)
		mail_box.pack_start(mail_btn, False, False, 0)

		top_box.pack_start(add_box, False, False, 10)
		top_box.pack_start(send_box, False, False, 10)
		top_box.pack_start(mail_box, False, False, 10)
		
		user_box = gtk.HBox(False, 5) #Separates the user Dp and his Nickname / PM
		dp_box = gtk.VBox(False, 0)
		nick_box = gtk.VBox(False, 0)

		user_dp = gtk.Image()
		MyTheme = gtk.icon_theme_get_default()
		MyIconPixbuf = MyTheme.load_icon("stock_smiley-3", 36, gtk.ICON_LOOKUP_FORCE_SVG)
		user_dp.set_from_pixbuf(MyIconPixbuf)
		user_dp.set_size_request(30,30)
		dp_box.pack_start(user_dp, False, False, 5)

		self.nick_btn = gtk.Button(self.my_instance.nick)
		self.nick_btn.set_relief(gtk.RELIEF_NONE)
		self.nick_btn.connect("clicked", self.new_nick)
		self.nick_entry = gtk.Entry()
		self.nick_entry.set_text(self.my_instance.nick)
		self.nick_entry.set_no_show_all(True)
		self.nick_entry.connect("activate", self.change_nick)
		self.pm_btn = gtk.Button("(Type a personal message)")
		self.pm_btn.set_relief(gtk.RELIEF_NONE)
		self.pm_btn.connect("clicked", self.new_pm)
		self.pm_entry = gtk.Entry()
		self.pm_entry.set_text("(Type a personal message)")
		self.pm_entry.set_no_show_all(True)
		self.pm_entry.connect("activate", self.change_pm)
		nick_box.pack_start(self.nick_btn, False, True, 0)
		nick_box.pack_start(self.nick_entry, False, True, 0)
		nick_box.pack_start(self.pm_btn, False, True, 0)
		nick_box.pack_start(self.pm_entry, False, True, 0)

		user_box.pack_start(dp_box, False, False, 3)
		user_box.pack_start(nick_box, False, False, 0)
		
		col = gtk.TreeViewColumn()
		render_pixbuf = gtk.CellRendererPixbuf()
		col.pack_start(render_pixbuf, expand=False)
		col.add_attribute(render_pixbuf, 'pixbuf', 0)
		render_text = gtk.CellRendererText()
		col.pack_start(render_text, expand=True)
		col.add_attribute(render_text, 'text', 1)
		col.pack_start(render_text, expand=False)
		col.add_attribute(render_text, 'text', 2)
		self.users_tree.append_column(col)

		column = gtk.TreeViewColumn('email', gtk.CellRendererText(),
					text=1)
		column.set_visible(False)
		self.users_tree.append_column(column)

		self.onlineg_img = self.users_tree.render_icon(gtk.STOCK_YES, 
							gtk.ICON_SIZE_SMALL_TOOLBAR)
		self.offlineg_img = self.users_tree.render_icon(gtk.STOCK_NO,
							gtk.ICON_SIZE_SMALL_TOOLBAR)
		self.online_img = self.users_tree.render_icon(gtk.STOCK_YES,
							gtk.ICON_SIZE_MENU)
		self.offline_img = self.users_tree.render_icon(gtk.STOCK_NO, 
							gtk.ICON_SIZE_MENU)
		
		self.online_iter = self.users_list.append(None, 
							(self.onlineg_img, 'Online', 'online')) #Online Group
		self.offline_iter = self.users_list.append(None, 
							(self.offlineg_img, 'Not Online', 'offline')) #Offline Group

	
		self.states = self.status_box()

		self.cw_statusbar = gtk.Statusbar()
		self.context_id = self.cw_statusbar.get_context_id("Statusbar")
		self.cw_statusbar.push(self.context_id, "Logged In")

		self.box.pack_start(top_box, False, True, 0)
		self.box.pack_start(user_box, False, True, 0)
		self.box.pack_start(self.users_tree, True, True, 0)
		self.box.pack_start(self.states, False, True, 0)
		self.box.pack_start(self.cw_statusbar, False, True, 0)

		self.contact_box.pack_start(self.box)
		self.main_box.pack_start(self.contact_box)
		self.window.set_size_request(370,500)
		self.window.show_all()
		

	def code_state(self, state, reverse=False):
		"""Switch between the states from user version to server version
			if reverse is true server -> user, NLN -> Online
			else user -> server, Online -> NLN"""
		states = {"NLN":"Online", "AWY":"Away", 
					"BSY":"Busy", "HDN":"Hidden", "FLN":"Offline"}
		reverse_states = {"Online":"NLN", "Away":"AWY",
					"Busy":"BSY", "Hidden":"HDN", "Offline":"FLN"}

		if reverse == True:
			return reverse_states[state]
		else:
			return states[state]

	def set_init_state(self, state):
		"""Set the initial state of the user in the status box"""
		states = ["Online", "Away", "Busy", "Hidden", "Offline"]
		user_state = self.code_state(state, False) #Returns user-friendly version of state
		model = self.states.get_model()
		iter_ = model.get_iter_root()
		status = int(model.get_string_from_iter(iter_))
		while user_state != states[status]:
			iter_ = model.iter_next(iter_)
			status = int(model.get_string_from_iter(iter_))
			print states[status]
		self.states.set_active_iter(iter_)
		
	def change_state(self, combobox, change=True):
		"""Change the State of the user"""
		print "Changing state"
		model = combobox.get_model()
		active = combobox.get_active()
		if active < 0:
			return None
		state = model[active][1] #Returns the state from the state combo box
								 #Returns the user-friendly version, ex: "Online"
		state = self.code_state(state, True) #Returns the server state, ex "NLN"
		
		if change == True: #prevents unnecessary looping when we set the state
			self.ns.change_state(state)

	def add_user(self, user_email, user_instance=None):
		"""If the user instance is set, that means the user signed 
			If the userinstance isnt, we just get an email from the lst and add it to
			the offline group"""
		if user_instance:
			nick = user_instance.nick
			email = user_instance.email
			user_iter = self.users_list.append(self.online_iter, 
							(self.online_img, nick, email)) #Iter for changing group location
			self.users_list.remove(self.offline_iters[email]) #remove from the offline group
			self.online_iters[email] = user_iter	#add to the online group
			if email in self.offline_iters.keys():
				del self.offline_iters[email]

			self.cw_statusbar.push(self.context_id, ""+email+": Came Online")
	
		else:
			user_iter = self.users_list.append(self.offline_iter, 
							(self.offline_img, user_email, user_email))
			self.offline_iters[user_email] = user_iter


	def rem_user(self, email):
		"""If the users signs out (FLN) we remove them from the online
			groups and into the offline, adding their iters to each group
			respectively."""
		self.users_list.remove(self.online_iters[email])
		user_iter = self.users_list.append(self.offline_iter, 
						(self.offline_img, email, email))
		self.offline_iters[email] = user_iter

		if email in self.online_iters.keys():
			del self.online_iters[email]

		self.cw_statusbar.push(self.context_id, ""+email+": Went Offline")


	def create_chat_window(self):
		if self.chat_window_created:
			return self.chat_window
		else:
			self.chat_window = chat.Window(self)
			self.chat_window_created = 1
			return self.chat_window

	def start_chat(self,treeview, path, view_column):
		"""User double clicks on a user to start chat"""
		t_iter = self.users_list.get_iter(path) #Return the iter of the buddy
		email = self.users_list.get_value(t_iter,2) #Retrieve their email from the hidden column
		user_instance = self.ns.online_users[email]
		if email not in self.open_chats.keys():
			session = self.ns.parse_sync("XFR", "SB").split(" ")
			#Ex: [XFR, 15, SB, 207.46.108.37:1863, CKI, 17262740.1050826919.32308]
			xfr = session[3].split(":")[0] # the address we'll connect to
			session_auth = session[5][:-2] # authentication string
			sess_details = [xfr, session_auth] #we dont need a session id here
			chat_window = self.create_chat_window()
			user_chat = chat.Session(self.my_instance, 
							chat_window, sess_details, user_instance, 1)

			chat_window.add_tab(user_chat.tab, user_instance.email)
			user_chat.inviter()
			self.open_chats[email] = user_chat
		else:
			user_chat = self.open_chats[email]
			user_chat.gui.chat_window.switch_page(email)

	def new_nick(self, button):
		"""Edit the users nickname"""
		self.nick_btn.hide()
		self.nick_entry.show()

	def change_nick(self, entry):
		"""User changed nick, send the new nick to the server"""
		new_nick = self.nick_entry.get_text()
		self.ns.change_nick(new_nick)
		self.nick_entry.hide()
		self.nick_btn.set_label(new_nick)
		self.nick_btn.show()

	def new_pm(self, button):
		"""Edit the users personal msg"""
		self.pm_btn.hide()
		self.pm_entry.show()

	def change_pm(self, entry):
		"""User changed p.m, send the new pm to the server"""
		new_pm = self.pm_entry.get_text()
		self.ns.change_pm(new_pm)
		self.pm_entry.hide()
		self.pm_btn.set_label(new_pm)
		self.pm_btn.show()

	def new_contact(self, button):
		"""User clicked on the add button. User wants to add a new buddy to their list"""
		self.add_user_dialog = gtk.Dialog("Add Contact", self.window, 0, buttons=None)
		self.add_user_email = gtk.Entry()
		self.add_user_email.set_text("contacts email")
		self.add_user_email.show()
		add_user = gtk.Button("Add")
		add_user.connect("clicked", self.add_contact)
		add_user.show()

		self.add_user_dialog.vbox.pack_start(self.add_user_email, False, False, 0)
		self.add_user_dialog.vbox.pack_start(add_user, False, False, 0)
		self.add_user_dialog.show()

	def add_contact(self, button):
		"""User entered the new buddys email address.. we send
			command to server to add the buddy to the list"""
		user_email = self.add_user_email.get_text()
		self.ns.add_contact(user_email)
		self.add_user_dialog.destroy()
		
		
def main():
	g = gui()
	g.login_window()


if __name__ == "__main__":
	main()
